---
title: Storage in Kastrax | Kastrax Docs
description: Overview of Kastrax's storage system and data persistence capabilities.
---

import { Tabs } from "nextra/components";

import { PropertiesTable } from "@/components/properties-table";
import { SchemaTable } from "@/components/schema-table";
import { StorageOverviewImage } from "@/components/storage-overview-image";

# KastraxStorage

`KastraxStorage` provides a unified interface for managing:

- **Suspended Workflows**: the serialized state of suspended workflows (so they can be resumed later)
- **Memory**: threads and messages per `resourceId` in your application
- **Traces**: OpenTelemetry traces from all components of Kastrax
- **Eval Datasets**: scores and scoring reasons from eval runs

<br />

<br />

<StorageOverviewImage />

Kastrax provides different storage providers, but you can treat them as interchangeable. Eg, you could use libsql in development but postgres in production, and your code will work the same both ways.

## Configuration

Kastrax can be configured with a default storage option:

```kotlin
import ai.kastrax.core.kastrax
import ai.kastrax.storage.libsql.LibSQLStore

val kastraxInstance = kastrax {
  storage = LibSQLStore(
    url = "file:./kastrax.db"
  )
}
```

## Data Schema

<Tabs items={['Messages', 'Threads', 'Workflows', 'Eval Datasets', 'Traces']}>
  <Tabs.Tab>
Stores conversation messages and their metadata. Each message belongs to a thread and contains the actual content along with metadata about the sender role and message type.

<br />
<SchemaTable
  columns={[
    {
      name: "id",
      type: "uuidv4",
      description: "Unique identifier for the message (format: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`)",
      constraints: [
        { type: "primaryKey" },
        { type: "nullable", value: false }
      ]
    },
    {
      name: "thread_id",
      type: "uuidv4",
      description: "Parent thread reference",
      constraints: [
        { type: "foreignKey", value: "threads.id" },
        { type: "nullable", value: false }
      ]
    },
    {
      name: "content",
      type: "text",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "role",
      type: "text",
      description: "Enum of `system | user | assistant | tool`",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "type",
      type: "text",
      description: "Enum of `text | tool-call | tool-result`",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "createdAt",
      type: "timestamp",
      description: "Used for thread message ordering",
      constraints: [{ type: "nullable", value: false }]
    }
  ]}
/>
  </Tabs.Tab>
  <Tabs.Tab>
Groups related messages together and associates them with a resource. Contains metadata about the conversation.

<br />
<SchemaTable
  columns={[
    {
      name: "id",
      type: "uuidv4",
      description: "Unique identifier for the thread (format: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`)",
      constraints: [
        { type: "primaryKey" },
        { type: "nullable", value: false }
      ]
    },
    {
      name: "resourceId",
      type: "text",
      description: "Primary identifier of the external resource this thread is associated with. Used to group and retrieve related threads.",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "title",
      type: "text",
      description: "Title of the conversation thread",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "metadata",
      type: "text",
      description: "Custom thread metadata as stringified JSON. Example:",
      example: {
        category: "support",
        priority: 1
      }
    },
    {
      name: "createdAt",
      type: "timestamp",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "updatedAt",
      type: "timestamp",
      description: "Used for thread ordering history",
      constraints: [{ type: "nullable", value: false }]
    }
  ]}
/>
  </Tabs.Tab>
  <Tabs.Tab>
When `suspend` is called on a workflow, its state is saved in the following format. When `resume` is called, that state is rehydrated.

<br />
<SchemaTable
  columns={[
    {
      name: "workflow_name",
      type: "text",
      description: "Name of the workflow",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "run_id",
      type: "uuidv4",
      description: "Unique identifier for the workflow execution. Used to track state across suspend/resume cycles (format: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`)",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "snapshot",
      type: "text",
      description: "Serialized workflow state as JSON. Example:",
      example: {
        value: { currentState: 'running' },
        context: {
          stepResults: {},
          attempts: {},
          triggerData: {}
        },
        activePaths: [],
        runId: '550e8400-e29b-41d4-a716-446655440000',
        timestamp: 1648176000000
      },
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "createdAt",
      type: "timestamp",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "updatedAt",
      type: "timestamp",
      description: "Last modification time, used to track state changes during workflow execution",
      constraints: [{ type: "nullable", value: false }]
    }
  ]}
/>
  </Tabs.Tab>
  <Tabs.Tab>
Stores eval results from running metrics against agent outputs.

<br />
<SchemaTable
  columns={[
    {
      name: "input",
      type: "text",
      description: "Input provided to the agent",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "output",
      type: "text",
      description: "Output generated by the agent",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "result",
      type: "jsonb",
      description: "Eval result data that includes score and details. Example:",
      example: {
        score: 0.95,
        details: {
          reason: "Response accurately reflects source material",
          citations: ["page 1", "page 3"]
        }
      },
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "agent_name",
      type: "text",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "metric_name",
      type: "text",
      description: "e.g Faithfulness, Hallucination, etc.",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "instructions",
      type: "text",
      description: "System prompt or instructions for the agent",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "test_info",
      type: "jsonb",
      description: "Additional test metadata and configuration",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "global_run_id",
      type: "uuidv4",
      description: "Groups related evaluation runs (e.g. all unit tests in a CI run)",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "run_id",
      type: "uuidv4",
      description: "Unique identifier for the run being evaluated (format: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`)",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "created_at",
      type: "timestamp",
      constraints: [{ type: "nullable", value: false }]
    }
  ]}
/>
  </Tabs.Tab>
  <Tabs.Tab>
Captures OpenTelemetry traces for monitoring and debugging.

<br />
<SchemaTable
  columns={[
    {
      name: "id",
      type: "text",
      description: "Unique trace identifier",
      constraints: [
        { type: "nullable", value: false },
        { type: "primaryKey" }
      ]
    },
    {
      name: "parentSpanId",
      type: "text",
      description: "ID of the parent span. Null if span is top level",
    },
    {
      name: "name",
      type: "text",
      description: "Hierarchical operation name (e.g. `workflow.myWorkflow.execute`, `http.request`, `database.query`)",
      constraints: [{ type: "nullable", value: false }],
    },
    {
      name: "traceId",
      type: "text",
      description: "Root trace identifier that groups related spans",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "scope",
      type: "text",
      description: "Library/package/service that created the span (e.g. `@kastrax/core`, `express`, `pg`)",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "kind",
      type: "integer",
      description: "`INTERNAL` (0, within process), `CLIENT` (1, outgoing calls), `SERVER` (2, incoming calls), `PRODUCER` (3, async job creation), `CONSUMER` (4, async job processing)",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "attributes",
      type: "jsonb",
      description: "User defined key-value pairs that contain span metadata",
    },
    {
      name: "status",
      type: "jsonb",
      description: "JSON object with `code` (UNSET=0, ERROR=1, OK=2) and optional `message`. Example:",
      example: {
        code: 1,
        message: "HTTP request failed with status 500"
      }
    },
    {
      name: "events",
      type: "jsonb",
      description: "Time-stamped events that occurred during the span",
    },
    {
      name: "links",
      type: "jsonb",
      description: "Links to other related spans",
      },
    {
      name: "other",
      type: "text",
      description: "Additional OpenTelemetry span fields as stringified JSON. Example:",
      example: {
        droppedAttributesCount: 2,
        droppedEventsCount: 1,
        instrumentationLibrary: "@opentelemetry/instrumentation-http"
      }
    },
    {
      name: "startTime",
      type: "bigint",
      description: "Nanoseconds since Unix epoch when span started",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "endTime",
      type: "bigint",
      description: "Nanoseconds since Unix epoch when span ended",
      constraints: [{ type: "nullable", value: false }]
    },
    {
      name: "createdAt",
      type: "timestamp",
      constraints: [{ type: "nullable", value: false }]
    }
  ]}
/>
  </Tabs.Tab>
</Tabs>

## Storage Providers

Kastrax supports the following providers:

- For local development, check out [LibSQL Storage](../../reference/storage/libsql.mdx)
- For production, check out [PostgreSQL Storage](../../reference/storage/postgresql.mdx)
- For serverless deployments, check out [Upstash Storage](../../reference/storage/upstash.mdx)
